Skip to content

JS: Introduce helper functions for event listeners#5495

Merged
osipxd merged 1 commit intorelease/3.xfrom
osipxd/typesafe-js-event
Apr 2, 2026
Merged

JS: Introduce helper functions for event listeners#5495
osipxd merged 1 commit intorelease/3.xfrom
osipxd/typesafe-js-event

Conversation

@osipxd
Copy link
Copy Markdown
Member

@osipxd osipxd commented Mar 28, 2026

Subsystem
JS/WasmJS client

Motivation
The existing approach was error-prone: it was easy to forget to call removeEventListener for one-time listeners, and the only correct implementation required a lateinit var to hold the callback reference so it could be removed inside itself.

Solution
Introduces a type-safe wrapper for addEventListener in the web source set (shared between js and wasmJs):

EventTarget.addEventListener<T>(event: String, once: Boolean = false, listener: (T) -> Unit): DisposableHandle
EventTarget.addEventListener<T>(event: String, vararg events: String, once: Boolean = false, listener: (T) -> Unit): DisposableHandle
  • Returns a DisposableHandle to remove the listener(s), eliminating the need to keep a separate lambda reference for cleanup
  • Supports multiple events: the listener fires once for whichever event occurs first
  • The once parameter automatically removes the listener after the first event fires
  • Uses (JsAny) -> Unit internally to bypass WasmJS instanceof checks that fail for non-standard event objects (e.g., from the ws npm package)

Refactors JsClientEngine, WasmJsClientEngine, and JsWebSocketSession (both js and wasmJs) to use these helpers.

@osipxd osipxd self-assigned this Mar 28, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 28, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Replaces manual DOM event listener wiring in JS/WASM client engines and WebSocket sessions with typed EventTarget.addEventListener extension overloads that return DisposableHandle; listeners are registered (optionally once) and disposed via the returned handle, removing explicit removeEventListener usage and adding Event.asString() platform implementations.

Changes

Cohort / File(s) Summary
New Utility Functions
ktor-client/ktor-client-core/web/src/io/ktor/client/utils/JsUtils.web.kt
Adds internal inline typed EventTarget.addEventListener overloads (reified T : Event) supporting once, multi-event registration, returning DisposableHandle; declares internal expect fun Event.asString(): String.
Event.asString implementations
ktor-client/ktor-client-core/js/src/io/ktor/client/utils/JsUtils.js.kt, ktor-client/ktor-client-core/wasmJs/src/io/ktor/client/utils/JsUtils.wasmJs.kt
Adds internal actual fun Event.asString(): String for JS and WASM targets (JSON.stringify of selected event fields); moves package to io.ktor.client.utils in the JS file.
Client Engines: awaitConnection
ktor-client/ktor-client-core/js/src/io/ktor/client/engine/js/JsClientEngine.kt, ktor-client/ktor-client-core/wasmJs/src/io/ktor/client/engine/js/WasmJsClientEngine.kt
Replaces manual separate "open"/"error" listener registration/removal with a single typed addEventListener<Event>("open", "error", once = true) disposable; disposes via returned handle on cancellation and retains close-on-cancel behavior.
WebSocket Sessions: event wiring & cleanup
ktor-client/ktor-client-core/js/src/io/ktor/client/plugins/websocket/JsWebSocketSession.kt, ktor-client/ktor-client-core/wasmJs/src/io/ktor/client/plugins/websocket/JsWebSocketSession.kt
Converts untyped listeners to typed MessageEvent/ErrorEvent/CloseEvent; uses one-time open/close listeners, removes unsafe casts and manual removeEventListener calls, and disposes stored DisposableHandles during job completion/cleanup.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • bjhham
  • zibet27
  • e5l
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.53% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: introducing helper functions for event listeners in JS/WasmJS client code.
Description check ✅ Passed The description follows the template structure and provides comprehensive motivation, solution details, and implementation notes that clearly explain the problem, approach, and refactoring changes.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch osipxd/typesafe-js-event

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@osipxd osipxd changed the title JS: Introduce helper functions for event listers JS: Introduce helper functions for event listeners Mar 28, 2026
@osipxd osipxd force-pushed the osipxd/typesafe-js-event branch 2 times, most recently from 0666f3b to f7a5d01 Compare March 30, 2026 23:44
@bjhham
Copy link
Copy Markdown
Contributor

bjhham commented Mar 31, 2026

Good call 👍

@osipxd osipxd force-pushed the osipxd/typesafe-js-event branch 3 times, most recently from 5a9cf5a to 96416ea Compare March 31, 2026 10:12
@osipxd osipxd marked this pull request as ready for review March 31, 2026 17:11
@osipxd osipxd requested a review from bjhham March 31, 2026 17:11
Comment on lines +28 to +39
// The callback parameter is JsAny, not Event, by design.
// Kotlin/WasmJS generates a JS adapter for each lambda based on its declared parameter type:
// a `(Event) -> Unit` adapter checks `x instanceof globalThis.Event` before invoking the lambda.
// The `ws` npm package defines its own `Event` hierarchy that does not extend `globalThis.Event`
// (see https://github.com/websockets/ws/issues/1818), so that check fails for every event fired
// by a Node.js WebSocket.
// Using `(JsAny) -> Unit` produces an adapter with no instanceof check, accepting any JS value.
// This is valid Kotlin: `(JsAny) -> Unit` is a subtype of `(Event) -> Unit` by contravariance.
// `unsafeCast<T>()` inside the body is a no-op — it changes only the compile-time type with no
// runtime check — so it never fails regardless of the actual JS object type.
@Suppress("RemoveExplicitTypeArguments") // Compiler fails to infer type arguments otherwise
val callback = { event: JsAny -> listener(event.unsafeCast<T>()) }
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It turned out to be not so simple 😅
But at least now this code is isolated and documented here

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! This is much better for event listeners listening a single event. I will try.
However, for the same listener registered to listen two events we will still need this utility function

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yeah, that's a good point. You'd think this would be part of the JS std lib by now.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the implementation to use once for single-event listeners and our custom mechanism for multi-event listeners

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 96416ea030

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@osipxd osipxd force-pushed the osipxd/typesafe-js-event branch from 96416ea to 0d74c0e Compare March 31, 2026 17:21
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@ktor-client/ktor-client-core/wasmJs/src/io/ktor/client/plugins/websocket/JsWebSocketSession.kt`:
- Around line 97-109: The error handler was mistakenly registered for the
"close" event so clean closes are treated as errors; in JsWebSocketSession
change the onError listener to listen for the "error" event (use the appropriate
Event/ErrorEvent type instead of CloseEvent) and keep its logic to create the
WebSocketException and call _closeReason.completeExceptionally(cause),
_incoming.close(cause) and _outgoing.cancel(); leave the existing one-time
"close" listener (which completes _closeReason normally, sends Frame.Close and
closes streams) unchanged so normal closes win.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 7557e285-ea60-4057-8716-15d7bbd2a830

📥 Commits

Reviewing files that changed from the base of the PR and between e7e32fd and 96416ea.

📒 Files selected for processing (5)
  • ktor-client/ktor-client-core/js/src/io/ktor/client/engine/js/JsClientEngine.kt
  • ktor-client/ktor-client-core/js/src/io/ktor/client/plugins/websocket/JsWebSocketSession.kt
  • ktor-client/ktor-client-core/wasmJs/src/io/ktor/client/engine/js/WasmJsClientEngine.kt
  • ktor-client/ktor-client-core/wasmJs/src/io/ktor/client/plugins/websocket/JsWebSocketSession.kt
  • ktor-client/ktor-client-core/web/src/io/ktor/client/utils/JsUtils.web.kt

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
ktor-client/ktor-client-core/web/src/io/ktor/client/utils/JsUtils.web.kt (1)

54-64: Potential race when multiple events fire in the same microtask.

When addOneTimeEventListener is called with multiple event names (e.g., "open", "error"), if both events fire before dispose() finishes removing all listeners, the callback could execute twice. JavaScript's single-threaded model doesn't fully protect against this since both events could be queued and processed sequentially before the synchronous dispose() loop completes for all event names.

In practice, for the current usage (awaitConnection with "open"/"error"), a WebSocket typically fires only one of these events, so this may be acceptable. However, the KDoc should document this limitation, or consider adding a guard (e.g., an AtomicBoolean or captured flag) to ensure single invocation.

♻️ Suggested documentation or guarded implementation

Option 1: Document the limitation in KDoc

 /**
  * Registers a one-time event listener that removes itself after the first event fires.
  * The listener is registered for all specified [events] and fires once for whichever event occurs first.
+ *
+ * Note: If multiple registered events fire in quick succession before [dispose] completes,
+ * the [listener] may be invoked more than once. Callers relying on single invocation should
+ * ensure the underlying event source only fires one of the registered events.
  *
  * The event is unsafe-cast to [T] before invoking [listener]. See [addEventListener] for why.

Option 2: Add a guard for guaranteed single invocation

 internal inline fun <reified T : Event> EventTarget.addOneTimeEventListener(
     vararg events: String,
     crossinline listener: (T) -> Unit
 ): DisposableHandle {
+    var fired = false
     lateinit var disposable: DisposableHandle
     disposable = addEventListener<T>(*events) { event ->
+        if (fired) return@addEventListener
+        fired = true
         disposable.dispose()
         listener(event)
     }
     return disposable
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ktor-client/ktor-client-core/web/src/io/ktor/client/utils/JsUtils.web.kt`
around lines 54 - 64, The addOneTimeEventListener implementation for EventTarget
can invoke the listener twice if multiple events fire before dispose removes all
listeners; update EventTarget.addOneTimeEventListener to capture a local guard
flag (e.g., var invoked = false) closed over by the returned listener so the
first invocation atomically checks and sets invoked (if already true, return),
then calls disposable.dispose() and listener(event); also add a short KDoc note
on EventTarget.addOneTimeEventListener explaining the single-invocation
guarantee. Ensure references to DisposableHandle, addEventListener and
EventTarget.addOneTimeEventListener are used when making the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@ktor-client/ktor-client-core/web/src/io/ktor/client/utils/JsUtils.web.kt`:
- Around line 54-64: The addOneTimeEventListener implementation for EventTarget
can invoke the listener twice if multiple events fire before dispose removes all
listeners; update EventTarget.addOneTimeEventListener to capture a local guard
flag (e.g., var invoked = false) closed over by the returned listener so the
first invocation atomically checks and sets invoked (if already true, return),
then calls disposable.dispose() and listener(event); also add a short KDoc note
on EventTarget.addOneTimeEventListener explaining the single-invocation
guarantee. Ensure references to DisposableHandle, addEventListener and
EventTarget.addOneTimeEventListener are used when making the change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 0eddc158-72c4-4071-8952-a1c16e623fd2

📥 Commits

Reviewing files that changed from the base of the PR and between 96416ea and 0d74c0e.

📒 Files selected for processing (5)
  • ktor-client/ktor-client-core/js/src/io/ktor/client/engine/js/JsClientEngine.kt
  • ktor-client/ktor-client-core/js/src/io/ktor/client/plugins/websocket/JsWebSocketSession.kt
  • ktor-client/ktor-client-core/wasmJs/src/io/ktor/client/engine/js/WasmJsClientEngine.kt
  • ktor-client/ktor-client-core/wasmJs/src/io/ktor/client/plugins/websocket/JsWebSocketSession.kt
  • ktor-client/ktor-client-core/web/src/io/ktor/client/utils/JsUtils.web.kt
🚧 Files skipped from review as they are similar to previous changes (1)
  • ktor-client/ktor-client-core/js/src/io/ktor/client/engine/js/JsClientEngine.kt

@osipxd osipxd force-pushed the osipxd/typesafe-js-event branch 2 times, most recently from c067e6b to 861faa1 Compare April 2, 2026 09:14
@osipxd osipxd enabled auto-merge (squash) April 2, 2026 09:18
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
ktor-client/ktor-client-core/wasmJs/src/io/ktor/client/plugins/websocket/JsWebSocketSession.kt (1)

97-102: Use event.message for a more informative error message in WebSocket error events.

Using "$event" produces unhelpful output like [object ErrorEvent]. The ErrorEvent type has a message property that provides actionable diagnostic information, as used in the corresponding engine error handlers.

♻️ Suggested improvement
         val onError = websocket.addEventListener<ErrorEvent>("error") { event ->
-            val cause = WebSocketException("$event")
+            val cause = WebSocketException(event.message)
             _closeReason.completeExceptionally(cause)
             _incoming.close(cause)
             _outgoing.cancel()
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@ktor-client/ktor-client-core/wasmJs/src/io/ktor/client/plugins/websocket/JsWebSocketSession.kt`
around lines 97 - 102, The error handler attached as onError constructs a
WebSocketException from "$event" which yields unhelpful "[object ErrorEvent]";
change the construction to use the ErrorEvent message (e.g., event.message,
falling back to event.toString() if empty) when creating the WebSocketException
in websocket.addEventListener, so
_closeReason.completeExceptionally(WebSocketException(...)),
_incoming.close(...), and _outgoing.cancel() carry the real diagnostic text;
update references in the onError handler where WebSocketException is created to
use event.message.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In
`@ktor-client/ktor-client-core/wasmJs/src/io/ktor/client/plugins/websocket/JsWebSocketSession.kt`:
- Around line 97-102: The error handler attached as onError constructs a
WebSocketException from "$event" which yields unhelpful "[object ErrorEvent]";
change the construction to use the ErrorEvent message (e.g., event.message,
falling back to event.toString() if empty) when creating the WebSocketException
in websocket.addEventListener, so
_closeReason.completeExceptionally(WebSocketException(...)),
_incoming.close(...), and _outgoing.cancel() carry the real diagnostic text;
update references in the onError handler where WebSocketException is created to
use event.message.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: bf59e66f-83da-483b-91ec-8aac499ababe

📥 Commits

Reviewing files that changed from the base of the PR and between 0d74c0e and 861faa1.

📒 Files selected for processing (5)
  • ktor-client/ktor-client-core/js/src/io/ktor/client/engine/js/JsClientEngine.kt
  • ktor-client/ktor-client-core/js/src/io/ktor/client/plugins/websocket/JsWebSocketSession.kt
  • ktor-client/ktor-client-core/wasmJs/src/io/ktor/client/engine/js/WasmJsClientEngine.kt
  • ktor-client/ktor-client-core/wasmJs/src/io/ktor/client/plugins/websocket/JsWebSocketSession.kt
  • ktor-client/ktor-client-core/web/src/io/ktor/client/utils/JsUtils.web.kt
🚧 Files skipped from review as they are similar to previous changes (2)
  • ktor-client/ktor-client-core/web/src/io/ktor/client/utils/JsUtils.web.kt
  • ktor-client/ktor-client-core/js/src/io/ktor/client/plugins/websocket/JsWebSocketSession.kt

@osipxd osipxd force-pushed the osipxd/typesafe-js-event branch from 861faa1 to 785825b Compare April 2, 2026 09:31
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
ktor-client/ktor-client-core/web/src/io/ktor/client/utils/JsUtils.web.kt (1)

57-57: Variable shadowing: consider renaming to avoid confusion.

The parameter events is shadowed by the local val events. While this works, it can be confusing during debugging or maintenance.

♻️ Suggested rename
-    val events = listOf(event, *events)
+    val allEvents = listOf(event, *events)
     lateinit var callback: (JsAny) -> Unit
-    val disposable = DisposableHandle { events.forEach { removeEventListener(it, callback) } }
+    val disposable = DisposableHandle { allEvents.forEach { removeEventListener(it, callback) } }
     callback = eventCallback<T> {
         if (once) disposable.dispose()
         listener(it)
     }
-    events.forEach { addEventListener(it, callback) }
+    allEvents.forEach { addEventListener(it, callback) }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ktor-client/ktor-client-core/web/src/io/ktor/client/utils/JsUtils.web.kt` at
line 57, The local declaration `val events = listOf(event, *events)` shadows the
function parameter `events`; rename the local variable (e.g., `combinedEvents`
or `eventsList`) and update all subsequent references in the same function to
use that new name so the parameter and local list are not ambiguous; ensure any
spread (`*events`) still references the original parameter and the rest of the
logic (like iterating or passing the merged list) uses the renamed local
variable.
ktor-client/ktor-client-core/wasmJs/src/io/ktor/client/plugins/websocket/JsWebSocketSession.kt (1)

97-102: Consider using the eventAsString pattern for safer error event handling.

The ws npm package (used for Node.js WebSockets) may emit error events that don't have a message property like the standard DOM ErrorEvent interface. The code in WasmJsClientEngine.kt already uses eventAsString(event) to safely serialize the entire event object when handling errors during connection. Apply the same pattern here for consistency and robustness across the error handling code path.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@ktor-client/ktor-client-core/wasmJs/src/io/ktor/client/plugins/websocket/JsWebSocketSession.kt`
around lines 97 - 102, The onError handler in JsWebSocketSession.kt constructs a
WebSocketException from event.message which may be missing for non-DOM
ErrorEvent instances; change it to use the same safe serialization used
elsewhere (call eventAsString(event) to produce the error text) and pass that
into WebSocketException, then continue to complete _closeReason exceptionally,
close _incoming with the cause, and cancel _outgoing as before; reference the
existing onError val, WebSocketException, _closeReason, _incoming, _outgoing,
and the eventAsString utility used in WasmJsClientEngine.kt to locate where to
update the handler.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In
`@ktor-client/ktor-client-core/wasmJs/src/io/ktor/client/plugins/websocket/JsWebSocketSession.kt`:
- Around line 97-102: The onError handler in JsWebSocketSession.kt constructs a
WebSocketException from event.message which may be missing for non-DOM
ErrorEvent instances; change it to use the same safe serialization used
elsewhere (call eventAsString(event) to produce the error text) and pass that
into WebSocketException, then continue to complete _closeReason exceptionally,
close _incoming with the cause, and cancel _outgoing as before; reference the
existing onError val, WebSocketException, _closeReason, _incoming, _outgoing,
and the eventAsString utility used in WasmJsClientEngine.kt to locate where to
update the handler.

In `@ktor-client/ktor-client-core/web/src/io/ktor/client/utils/JsUtils.web.kt`:
- Line 57: The local declaration `val events = listOf(event, *events)` shadows
the function parameter `events`; rename the local variable (e.g.,
`combinedEvents` or `eventsList`) and update all subsequent references in the
same function to use that new name so the parameter and local list are not
ambiguous; ensure any spread (`*events`) still references the original parameter
and the rest of the logic (like iterating or passing the merged list) uses the
renamed local variable.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 78a41874-e97a-4c64-8409-011a55e7308c

📥 Commits

Reviewing files that changed from the base of the PR and between 861faa1 and 785825b.

📒 Files selected for processing (5)
  • ktor-client/ktor-client-core/js/src/io/ktor/client/engine/js/JsClientEngine.kt
  • ktor-client/ktor-client-core/js/src/io/ktor/client/plugins/websocket/JsWebSocketSession.kt
  • ktor-client/ktor-client-core/wasmJs/src/io/ktor/client/engine/js/WasmJsClientEngine.kt
  • ktor-client/ktor-client-core/wasmJs/src/io/ktor/client/plugins/websocket/JsWebSocketSession.kt
  • ktor-client/ktor-client-core/web/src/io/ktor/client/utils/JsUtils.web.kt
🚧 Files skipped from review as they are similar to previous changes (1)
  • ktor-client/ktor-client-core/js/src/io/ktor/client/engine/js/JsClientEngine.kt

@osipxd osipxd disabled auto-merge April 2, 2026 09:41
@osipxd osipxd force-pushed the osipxd/typesafe-js-event branch from 785825b to c27ff1d Compare April 2, 2026 09:52
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
ktor-client/ktor-client-core/web/src/io/ktor/client/utils/JsUtils.web.kt (1)

57-57: Variable shadows parameter name.

The local val events shadows the vararg events parameter. While this works correctly, consider renaming for clarity.

♻️ Suggested rename for clarity
 ): DisposableHandle {
-    val events = listOf(event, *events)
+    val allEvents = listOf(event, *events)
     lateinit var callback: (JsAny) -> Unit
-    val disposable = DisposableHandle { events.forEach { removeEventListener(it, callback) } }
+    val disposable = DisposableHandle { allEvents.forEach { removeEventListener(it, callback) } }
     callback = eventCallback<T> {
         if (once) disposable.dispose()
         listener(it)
     }
-    events.forEach { addEventListener(it, callback) }
+    allEvents.forEach { addEventListener(it, callback) }
     return disposable
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ktor-client/ktor-client-core/web/src/io/ktor/client/utils/JsUtils.web.kt` at
line 57, The local declaration val events = listOf(event, *events) shadows the
vararg parameter named events; rename the local variable (e.g., combinedEvents
or eventsList) wherever used in the function to avoid shadowing and improve
clarity (update the declaration and all subsequent references in the function
such as usages of the newly named combinedEvents/eventsList instead of events).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@ktor-client/ktor-client-core/web/src/io/ktor/client/utils/JsUtils.web.kt`:
- Line 57: The local declaration val events = listOf(event, *events) shadows the
vararg parameter named events; rename the local variable (e.g., combinedEvents
or eventsList) wherever used in the function to avoid shadowing and improve
clarity (update the declaration and all subsequent references in the function
such as usages of the newly named combinedEvents/eventsList instead of events).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 707e9e8e-00f5-4d23-a3fe-6db1e7861256

📥 Commits

Reviewing files that changed from the base of the PR and between 785825b and c27ff1d.

📒 Files selected for processing (7)
  • ktor-client/ktor-client-core/js/src/io/ktor/client/engine/js/JsClientEngine.kt
  • ktor-client/ktor-client-core/js/src/io/ktor/client/plugins/websocket/JsWebSocketSession.kt
  • ktor-client/ktor-client-core/js/src/io/ktor/client/utils/JsUtils.js.kt
  • ktor-client/ktor-client-core/wasmJs/src/io/ktor/client/engine/js/WasmJsClientEngine.kt
  • ktor-client/ktor-client-core/wasmJs/src/io/ktor/client/plugins/websocket/JsWebSocketSession.kt
  • ktor-client/ktor-client-core/wasmJs/src/io/ktor/client/utils/JsUtils.wasmJs.kt
  • ktor-client/ktor-client-core/web/src/io/ktor/client/utils/JsUtils.web.kt

@osipxd osipxd merged commit 112dbf0 into release/3.x Apr 2, 2026
17 of 19 checks passed
@osipxd osipxd deleted the osipxd/typesafe-js-event branch April 2, 2026 10:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants